Reranker를 추가할 때 얻는 것과 비용
Reranker를 추가할 때 얻는 것과 비용
Reranker는 검색기가 놓친 문서를 새로 만드는 단계가 아니라 이미 찾은 후보의 순서를 더 정밀하게 바꾸는 단계다. Bi-encoder는 document vector를 미리 계산해 대규모 후보를 빠르게 찾지만 query와 document token이 직접 상호작용하지 않는다. Cross-encoder는 둘을 함께 읽어 부정, exact term과 조건 관계를 더 잘 평가할 수 있는 대신 후보마다 추론 비용이 든다. Candidate recall을 먼저 확보하고 rerank depth, batch, timeout과 fallback을 평가셋으로 결정해야 한다.
목차
- #검색 결과가 있는데도 답이 틀리는 경우
- #Retriever와 Reranker의 책임은 다르다
- #Bi-encoder와 Cross-encoder의 계산 차이
- #Reranker가 개선할 수 있는 문제
- #Reranker가 해결하지 못하는 문제
- #Candidate Recall이 품질 상한이다
- #몇 개의 후보를 다시 정렬할까
- #Passage 길이와 Truncation을 확인한다
- #점수는 서로 다른 단계에서 다른 의미를 가진다
- #Batch와 Parallelism으로 지연을 관리한다
- #Timeout과 Fallback을 설계한다
- #재구성한 TypeScript Rerank Pipeline
- #다양성과 Parent 중복을 함께 처리한다
- #Query 유형별로 Reranker를 선택한다
- #평가를 단계별로 나눈다
- #운영 비용과 Cache
- #관찰 지표와 Debug 정보
- #마무리
- #참고 자료
- #관련 노트
검색 결과가 있는데도 답이 틀리는 경우
RAG 답변이 틀려 검색 결과를 확인했는데 정답 문서가 이미 top-20 안에 있는 경우가 있다.
Query: PAY-1042 오류에서 자동 재시도를 해도 되나요?
1위 결제 timeout의 일반 재시도 정책
2위 PAY-1041 인증 오류
3위 결제 API 공통 오류 처리
...
14위 PAY-1042에서는 자동 재시도 금지
Generator에 top-5만 넘기면 정답은 문맥에 들어오지 않는다. Top-20을 모두 넘기면 찾을 가능성은 있지만 불필요한 문서와 token이 크게 늘어난다.
Reranker는 1차 검색의 top-20을 query와 다시 비교해 14위 문서를 위로 올리는 역할을 한다.
flowchart LR
Q[Query] --> R[Fast Retriever]
I[(Large Index)] --> R
R --> C[Top 50 Candidates]
Q --> X[Cross-encoder Reranker]
C --> X
X --> K[Top 8 Evidence]
K --> G[Generator]1차 retriever는 수백만 document에서 정답 후보를 놓치지 않는 것이 중요하다. Reranker는 그 작은 후보 집합 안에서 상위 순서를 정밀하게 만드는 데 집중한다.
정답이 retriever candidate 안에 없다면 reranker model을 교체해도 복구할 수 없다. Candidate depth, hybrid 검색, chunking과 filter를 먼저 점검한다.
Retriever와 Reranker의 책임은 다르다
두 단계를 하나의 “검색 점수”로 뭉치면 어디를 개선해야 하는지 알기 어렵다.
| 단계 | 주요 목표 | 대표 지표 | 허용 비용 |
|---|---|---|---|
| Candidate retrieval | 정답을 후보에 포함 | Recall@50, Hit@100 | 매우 낮아야 함 |
| Fusion | 여러 retriever 후보 통합 | Recall, nDCG | 낮음 |
| Reranking | 상위 관련 순서 개선 | MRR, nDCG@10 | 후보 수만큼 허용 |
| Context selection | 근거 다양성과 token 조립 | evidence coverage | 제한된 최적화 |
| Generation | 근거로 답변 생성 | correctness, faithfulness | 가장 높은 비용 가능 |
Reranker에게 “답을 생성하라”고 시키기보다 각 query-document pair의 관련성을 일관된 score로 반환하게 한다.
type RerankInput = {
query: string;
documents: Array<{
id: string;
title?: string;
text: string;
}>;
};
type RerankScore = {
documentId: string;
score: number;
originalRank: number;
};
Bi-encoder와 Cross-encoder의 계산 차이
Bi-encoder는 query와 document를 각각 encode한다.
q = queryEncoder(query)
d = documentEncoder(document)
score = similarity(q, d)
Document vector는 색인 시 한 번 계산해 저장할 수 있다. Query당 한 번 encode하고 ANN index에서 가까운 vector를 찾으므로 대규모 검색에 적합하다.
Cross-encoder는 query와 document를 한 입력으로 연결해 함께 처리한다.
input = [CLS] query [SEP] document [SEP]
score = crossEncoder(input)
Query token과 document token이 attention에서 직접 상호작용할 수 있어 “재시도”와 “금지”, 특정 오류 code와 그 설명의 관계를 더 세밀하게 볼 수 있다. 그러나 document만 미리 encode해 재사용하기 어렵고 query마다 candidate 수만큼 pair inference가 필요하다.
Corpus = 1,000,000 documents
Cross-encoder로 전부 평가
-> Query당 1,000,000 pair inference
Bi-encoder top 50 + Cross-encoder
-> 빠른 index search + 50 pair inference
Sentence-BERT 연구는 pair를 함께 처리하는 BERT 방식의 높은 계산 비용과, 문장을 독립 embedding해 유사도를 계산하는 bi-encoder의 효율 차이를 설명한다. Rerank 구조는 두 방식의 강점을 단계별로 배치한다.
Reranker가 개선할 수 있는 문제
부정과 조건 관계
A: PAY-1042에서는 자동 재시도를 허용한다.
B: PAY-1042에서는 자동 재시도를 허용하지 않는다.
Single-vector similarity에서는 두 문서가 모두 query와 가깝게 나올 수 있다. Cross-encoder는 query의 “해도 되나요”와 passage의 부정 표현을 함께 볼 수 있다.
Exact entity의 위치
Query: Pro 요금제의 보존 기간
Document A: Basic 30일, Pro 90일
Document B: Pro 30일, Enterprise 90일
두 문서는 같은 term과 숫자를 공유하지만 관계가 다르다. Pair-level interaction이 정확한 연결을 평가하는 데 도움이 된다.
긴 자연어 질문의 핵심 조건
사용자가 관리자이고 SSO 계정이면서 긴급 복구 중일 때 승인 생략 가능 여부
1차 검색은 일부 조건만 맞는 문서를 높게 올릴 수 있다. Reranker는 여러 조건을 동시에 만족하는 passage를 우선할 수 있다.
Hybrid 후보의 공통 기준
BM25와 dense score의 범위는 다르다. Hybrid Search로 키워드와 의미 검색 결합하기에서 RRF로 합친 뒤 reranker가 모든 후보를 동일한 query-passage 모델로 평가하면 최종 정밀 순서를 만들 수 있다.
Reranker가 해결하지 못하는 문제
Reranker를 만능 검색 개선기로 두면 잘못된 기대가 생긴다.
| 문제 | Reranker가 해결하기 어려운 이유 |
|---|---|
| 정답 문서가 색인에 없음 | 후보 자체가 존재하지 않음 |
| Parser가 표를 깨뜨림 | 입력 passage에 관계 정보가 없음 |
| 정답이 candidate 밖 | Reranker는 새 후보를 검색하지 않음 |
| 권한 filter 누락 | 관련성 model은 보안 정책이 아님 |
| 구버전 문서만 후보 | 최신성 metadata 문제 |
| 답이 여러 chunk에 분리 | Pair 하나에 완전한 근거가 없음 |
| Generator가 근거를 무시 | 생성 단계 문제 |
또한 일반 domain에서 학습된 reranker가 내부 약어와 업무 relevance를 잘 이해하지 못할 수 있다. 높은 score가 사실성이나 source authority를 의미하지 않는다.
Reranker relevance score
!= 문서의 진실 확률
!= 최신성 점수
!= 접근 권한
!= 답변 confidence
Unauthorized document를 reranker에 보낸 뒤 점수가 낮으면 버리는 구조는 이미 data exposure다. Tenant와 권한 filter를 candidate retrieval 전에 강제한다.
Candidate Recall이 품질 상한이다
Reranker 성능을 평가하기 전에 oracle experiment를 해 볼 수 있다.
Retriever top-10에 정답 포함률 = 72%
Retriever top-50에 정답 포함률 = 91%
Retriever top-100에 정답 포함률 = 94%
완벽한 reranker도 top-50 후보만 받으면 최대 91% case에서만 정답을 위로 올릴 수 있다. 이를 candidate recall ceiling으로 볼 수 있다.
function candidateRecall(
cases: EvaluationCase[],
depth: number,
): number {
const hits = cases.filter((testCase) =>
testCase.retrieved.slice(0, depth).some((candidate) =>
testCase.relevantIds.includes(candidate.documentId),
),
).length;
return hits / cases.length;
}
Hybrid search로 lexical과 dense 후보를 합쳐 recall을 높인 뒤 rerank하는 순서가 자연스럽다.
Dense top 50 recall 86%
Lexical top 50 recall 81%
Hybrid union recall 94%
Reranker top 8 hit 89%
숫자는 설명용 가상값이다. 중요한 것은 각 단계의 상한과 손실을 분리해 보는 방식이다.
몇 개의 후보를 다시 정렬할까
Rerank depth를 늘리면 recall ceiling은 올라가지만 비용과 latency가 거의 후보 수에 따라 증가한다.
total pairs = queries × candidates per query
| Rerank 후보 | 장점 | 비용 |
|---|---|---|
| 10 | 빠르고 저렴 | 정답이 11위 이하이면 복구 불가 |
| 30 | 실용적 중간 범위 | Query당 30 pair |
| 100 | 높은 candidate recall | Batch·GPU와 latency 부담 |
| 500 | 넓은 재정렬 | Online 요청에는 과도할 수 있음 |
최종 context가 8개라고 rerank도 8개만 하면 1차 순서를 거의 바꾸지 못한다. 반대로 top-100의 candidate recall이 top-50과 거의 같다면 두 배 비용의 이익이 없다.
Evaluation에서 depth별 curve를 그린다.
depth -> candidate Recall -> reranked nDCG@10 -> p95 latency -> cost/query
Query category별 최적 depth가 다를 수 있다. Exact code query는 lexical 1위가 강해 작은 depth로 충분하고, 넓은 자연어 질문은 더 많은 dense candidate가 필요할 수 있다.
Passage 길이와 Truncation을 확인한다
Cross-encoder에도 최대 input token이 있다. Query와 passage, special token이 한 window를 공유한다.
max input = 512 tokens
query = 80
special = 3
passage = 최대 429
Passage가 800 token인데 뒤쪽에 정답이 있으면 조용히 truncate되어 낮은 score를 받을 수 있다.
type RerankDocument = {
id: string;
text: string;
tokenCount: number;
truncated: boolean;
};
function preparePair(
query: string,
document: RerankDocument,
maxTokens: number,
): PreparedPair {
const queryTokens = tokenizer.encode(query);
const available = maxTokens - queryTokens.length - SPECIAL_TOKEN_COUNT;
const documentTokens = tokenizer.encode(document.text);
return {
queryTokens,
documentTokens: documentTokens.slice(0, available),
truncated: documentTokens.length > available,
};
}
항상 앞부분만 남기는 대신 query와 lexical match 주변 window를 선택하거나 long-document reranker를 검토할 수 있다. Heading과 title을 prefix로 넣을 때도 token budget에 포함한다.
Truncation rate가 높다면 RAG에서 Chunk 크기를 정하는 기준의 chunk policy와 reranker 입력 설계를 함께 조정한다.
점수는 서로 다른 단계에서 다른 의미를 가진다
Pipeline에는 여러 score가 있다.
type RankedCandidate = {
documentId: string;
lexicalScore?: number;
denseScore?: number;
fusionScore: number;
rerankerScore?: number;
finalRank: number;
};
Reranker output도 model에 따라 logit, relevance score 또는 normalized probability처럼 보이는 값일 수 있다. 모델 문서와 학습 objective를 확인한다. 서로 다른 reranker version의 0.8을 직접 비교하지 않는다.
reranker score 0.72
= 해당 model과 input 형식에서의 ranking signal
!= 답변이 72% 확률로 정확함
Threshold로 candidate를 제거하려면 labeled data로 precision-recall을 보정한다. Top-n sorting만 사용할 때도 모든 score가 낮은 no-answer query를 처리할 별도 abstention 신호가 필요하다.
Reranker score가 같을 때는 deterministic tie-breaker를 둔다.
1. reranker score desc
2. exact match count desc
3. original fusion rank asc
4. document ID asc
Batch와 Parallelism으로 지연을 관리한다
Cross-encoder는 후보를 batch로 처리할 수 있다.
후보 40개
batch size 8
-> 5 inference batches
Batch를 키우면 accelerator utilization이 좋아질 수 있지만 memory, padding waste와 queue 대기가 증가한다. Passage 길이가 크게 다르면 비슷한 길이끼리 묶어 padding을 줄일 수 있다.
function bucketByLength(documents: RerankDocument[]): RerankDocument[][] {
return [...documents]
.sort((a, b) => a.tokenCount - b.tokenCount)
.reduce<RerankDocument[][]>((batches, document) => {
const last = batches.at(-1);
if (!last || last.length >= 8) batches.push([document]);
else last.push(document);
return batches;
}, []);
}
Online service에서는 여러 query의 pair를 dynamic batching할 수도 있다. 하지만 batch를 채우려고 기다리는 시간이 p50 latency를 늘릴 수 있으므로 최대 wait time을 둔다.
batch trigger
size >= 32
OR oldest request waited >= 5ms
숫자는 가상 예시다. CPU/GPU, model size, input length와 traffic pattern으로 load test한다.
Timeout과 Fallback을 설계한다
Reranker가 느리거나 실패했다고 전체 검색을 항상 실패시킬 필요는 없다. 그러나 fallback이 품질에 미치는 영향을 표시해야 한다.
flowchart TD
C[Fused Candidates] --> R[Reranker]
R -->|success| S[Reranked Results]
R -->|timeout| P{Query risk}
P -->|낮음| F[Original Fusion Order]
P -->|높음| A[답변 보류 또는 추가 질문]| 상황 | 처리 예시 |
|---|---|
| FAQ 검색 reranker timeout | Fusion 순위 fallback |
| 보안 정책·삭제 절차 | 검색 실패로 처리 또는 사람 확인 |
| 일부 batch만 실패 | 완전한 fallback 또는 성공 batch만 사용 금지 검토 |
| Model overload | 작은 model 또는 rerank depth 축소 |
일부 candidate만 score를 받은 상태에서 그 후보를 위에 놓으면 공정하지 않은 순위가 된다. 전체 request를 fallback하거나 명시된 score merging 정책이 필요하다.
type RerankResult = {
mode: "RERANKED" | "FUSION_FALLBACK";
modelVersion?: string;
degradedReason?: string;
candidates: RankedCandidate[];
};
Circuit breaker가 열렸을 때도 mode를 로그와 downstream answer policy에 전달한다.
재구성한 TypeScript Rerank Pipeline
다음은 특정 vendor SDK가 아닌 책임 분리를 보여 주는 예시다.
type RerankRequest = {
query: string;
candidates: Array<{
documentId: string;
title: string;
text: string;
fusionRank: number;
fusionScore: number;
}>;
topN: number;
timeoutMs: number;
};
async function rerank(request: RerankRequest): Promise<RerankResult> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), request.timeoutMs);
try {
const scored = await reranker.score({
query: request.query,
documents: request.candidates.map((candidate) => ({
id: candidate.documentId,
text: `${candidate.title}\n\n${candidate.text}`,
})),
signal: controller.signal,
});
const scoreById = new Map(
scored.map((item) => [item.documentId, item.score]),
);
const ranked = request.candidates
.map((candidate) => ({
...candidate,
rerankerScore: scoreById.get(candidate.documentId),
}))
.filter((candidate) => candidate.rerankerScore !== undefined)
.sort((left, right) =>
right.rerankerScore! - left.rerankerScore! ||
left.fusionRank - right.fusionRank ||
left.documentId.localeCompare(right.documentId),
)
.slice(0, request.topN)
.map((candidate, index) => ({ ...candidate, finalRank: index + 1 }));
if (ranked.length !== Math.min(request.topN, request.candidates.length)) {
throw new Error("reranker returned incomplete scores");
}
return {
mode: "RERANKED",
modelVersion: reranker.version,
candidates: ranked,
};
} catch (error) {
if (!isAllowedFallback(error)) throw error;
return {
mode: "FUSION_FALLBACK",
degradedReason: classifyRerankFailure(error),
candidates: request.candidates
.slice(0, request.topN)
.map((candidate, index) => ({ ...candidate, finalRank: index + 1 })),
};
} finally {
clearTimeout(timer);
}
}
예시는 input schema, access filter와 retry가 이미 upstream에서 처리됐다고 가정한다. Reranker request에 unauthorized text를 넣지 않는다. Timeout retry는 같은 deterministic inference라면 가능하지만 과부하를 증폭하지 않도록 전체 deadline과 budget을 따른다.
다양성과 Parent 중복을 함께 처리한다
Reranker가 가장 관련 있는 passage만 정렬하면 같은 parent의 인접 chunk가 상위를 모두 차지할 수 있다.
1. document A / chunk 4
2. document A / chunk 5
3. document A / chunk 3
4. document B / chunk 2
최종 context에 A의 거의 같은 내용만 들어가면 다른 필수 근거를 놓친다. Parent별 cap이나 Maximum Marginal Relevance와 비슷한 다양성 penalty를 적용할 수 있다.
function selectDiverse(
candidates: RerankedChunk[],
maxPerParent: number,
topN: number,
): RerankedChunk[] {
const counts = new Map<string, number>();
const selected: RerankedChunk[] = [];
for (const candidate of candidates) {
const count = counts.get(candidate.parentId) ?? 0;
if (count >= maxPerParent) continue;
selected.push(candidate);
counts.set(candidate.parentId, count + 1);
if (selected.length === topN) break;
}
return selected;
}
무조건 parent당 1개로 제한하면 하나의 긴 section에서 필요한 두 chunk를 놓칠 수 있다. Multi-evidence 평가셋으로 cap과 neighbor expansion 순서를 정한다.
Query 유형별로 Reranker를 선택한다
모든 query가 비싼 cross-encoder를 필요로 하지는 않는다.
Exact ID + lexical top1 exact match + active source
-> reranker 생략 가능 후보
긴 자연어 + 여러 dense/lexical 후보 충돌
-> reranker 가치가 큼
Structured lookup
-> DB query가 우선
function shouldRerank(context: RetrievalContext): boolean {
if (context.queryClass === "STRUCTURED_LOOKUP") return false;
if (
context.queryClass === "EXACT_IDENTIFIER" &&
context.topCandidate.exactMatch &&
context.topCandidate.authoritative
) {
return false;
}
return context.candidates.length > 1;
}
이 routing도 evaluation으로 검증한다. 생략 rule 때문에 어려운 exact query의 예외 문서를 놓칠 수 있다.
Latency budget에 따라 model tier를 나눌 수도 있다.
| Tier | 적용 | Rerank 방식 |
|---|---|---|
| Fast | 자동완성, 낮은 위험 | 생략 또는 작은 model top-10 |
| Standard | 일반 RAG 질문 | cross-encoder top-30 |
| High assurance | 정책·운영 결정 | 넓은 후보 + 강한 model + 검증 |
숫자와 model 선택은 가상 구조이며 실제 SLA와 평가로 정한다.
평가를 단계별로 나눈다
Reranker 도입 전후 최종 답변 accuracy만 비교하면 원인을 알기 어렵다.
1. Retrieval candidate Recall@N
2. Reranker MRR / nDCG@k / Hit@k
3. Context evidence coverage와 중복률
4. End-to-end 답변·인용 정확도
5. p50/p95/p99 latency와 cost/query
다음 구성을 ablation test한다.
| 구성 | 목적 |
|---|---|
| Dense only | Semantic baseline |
| Lexical only | Exact baseline |
| Hybrid fusion | Candidate recall 증가 확인 |
| Hybrid + reranker | 정밀 순위의 추가 효과 |
| Oracle reranker | Candidate ceiling 추정 |
type RerankEvaluationRow = {
queryId: string;
category: string;
relevantIds: string[];
candidateDepth: number;
beforeRanks: number[];
afterRanks: number[];
truncatedCandidates: number;
latencyMs: number;
};
Hard negative를 포함한다. Query term은 많이 겹치지만 답이 반대인 문서, 같은 제품의 구버전, 비슷한 다른 error code가 좋은 사례다.
Positive: PAY-1042에서는 자동 재시도하지 않는다.
Hard negative: PAY-1041에서는 최대 2회 재시도한다.
Hard negative: PAY-1042 지표는 5분 간격으로 집계한다.
Reranker가 hard negative를 실제로 내리는지 category별로 본다.
운영 비용과 Cache
Reranker 비용은 대략 query 수, 후보 수와 input token 길이에 따라 증가한다.
daily pair inference
= daily queries × average rerank candidates
Query가 하루 100,000건이고 평균 40개 후보라면 4,000,000 pair를 평가한다. 실제 비용은 model과 배치 방식에 따라 다르지만 candidate depth가 작은 설정처럼 보여도 전체 규모에서는 중요하다.
Cache key에는 query normalization, candidate content version과 reranker model version이 필요하다.
const rerankCacheKey = sha256(JSON.stringify({
normalizedQuery,
candidates: candidates.map((item) => ({
id: item.documentId,
contentHash: item.contentHash,
})),
modelVersion: reranker.version,
inputTemplateVersion: "rerank-input-v3",
}));
Document가 바뀌거나 model을 교체하면 이전 score를 재사용하면 안 된다. Query에 개인정보가 있으면 cache key와 payload 저장, tenant 분리를 주의한다.
비용을 줄이는 다른 방법도 있다.
- Query class별 reranker 생략
- Candidate depth 감소
- 작은 model을 1단계, 큰 model을 어려운 query에만 사용
- Offline evaluation으로 bi-encoder를 개선
- Dynamic batching과 길이 bucket
- 반복되는 공개 query만 안전하게 cache
품질 저하 없이 어느 최적화가 가능한지는 실제 rank movement와 query category에서 확인한다.
관찰 지표와 Debug 정보
Reranker가 실제로 가치를 만드는지 지속적으로 측정한다.
| 지표 | 의미 |
|---|---|
| rerank invocation rate | 어느 query에 적용되는가 |
| candidate depth | 비용의 핵심 driver |
| rank movement | 원래 순위를 얼마나 바꾸는가 |
| relevant promotion rate | 정답을 top-k로 올린 비율 |
| harmful demotion rate | 정답을 top-k 밖으로 내린 비율 |
| truncated input rate | model이 근거를 못 보는 비율 |
| batch size / padding ratio | accelerator 효율 |
| p50·p95·p99 latency | 사용자 지연과 tail |
| timeout / fallback rate | 품질 저하 빈도 |
| score distribution | model·corpus drift |
| cost per successful answer | 실제 효율 |
{
"event": "retrieval.rerank.completed",
"queryId": "qry-83",
"queryClass": "MIXED",
"candidateCount": 40,
"selectedCount": 8,
"modelVersion": "reranker-example-v3",
"topDocumentOriginalRank": 14,
"topDocumentFinalRank": 1,
"truncatedCount": 2,
"mode": "RERANKED",
"elapsedMs": 96
}
Debug 화면에는 candidate별 lexical, dense, fusion, reranker score와 content hash를 분리해 표시한다. 최종 score 하나만 보이면 어느 단계가 문서를 올렸는지 알 수 없다.
마무리
Reranker는 검색 pipeline의 두 번째 기회다. 빠른 retriever가 넓게 모은 후보 안에서 query와 passage를 함께 읽고 세밀한 관련성을 다시 판단한다.
Reranker의 품질 상한은 후보 recall이고, 운영 비용의 핵심은 다시 평가하는 query-document pair 수와 token 길이다.
실무 적용 기준은 다음과 같다.
- 정답이 candidate 안에 있는지 먼저 확인한다.
- Retriever는 recall, reranker는 상위 precision과 ranking에 집중시킨다.
- Hybrid 후보를 충분히 모은 뒤 공통 모델로 rerank한다.
- Candidate depth별 recall ceiling과 latency curve를 측정한다.
- 최종 context 수보다 넓은 후보를 reranker에 제공한다.
- Query와 passage가 model input에서 truncate되는 방식을 확인한다.
- Fusion score와 reranker score를 별도 필드로 보존한다.
- Batch, padding, queue wait와 accelerator 사용률을 함께 최적화한다.
- Timeout 시 전체 fallback인지 답변 보류인지 위험도별로 정한다.
- Unauthorized candidate는 reranker 전에 제거한다.
- Parent 중복과 evidence 다양성을 최종 선택 단계에서 처리한다.
- Query class별로 reranker 적용과 model tier를 결정한다.
- Hard negative가 포함된 evaluation으로 harmful demotion도 측정한다.
- Cache에 candidate content와 model·template version을 묶는다.
검색 상위 후보를 더 많이 model에 넣는 것만으로는 정답이 잘 보인다는 보장이 없다. Reranker는 넓은 recall과 작은 최종 context 사이에서 정답 근거를 위로 끌어올리는 단계이며, 그 효과가 추가 추론 비용보다 큰지를 데이터로 확인해야 한다.
참고 자료
- Passage Re-ranking with BERT
- Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks
- Augmented SBERT: Data Augmentation for Improving Bi-Encoders
- Sentence Transformers - Retrieve and Re-Rank
- BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models